{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "attempted-ideal",
   "metadata": {},
   "source": [
    "## 函数传参"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "correct-england",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "140715867453248\n",
      "140715867453248\n",
      "140715867453536\n",
      "140715867453248\n"
     ]
    }
   ],
   "source": [
    "# 不可变对象传参\n",
    "def change(a):\n",
    "    print(id(a))   # 指向的是同一个对象\n",
    "    a=10\n",
    "    print(id(a))   # 一个新对象\n",
    " \n",
    "a=1\n",
    "print(id(a))\n",
    "change(a)\n",
    "print(id(a))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "subtle-begin",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1653232699328 [1, 2, 3]\n",
      "1653232699328 [1, 2, 3]\n",
      "1653232699328 [1, 2, 3, [4, 5]]\n",
      "1653232699328 [1, 2, 3, [4, 5]]\n"
     ]
    }
   ],
   "source": [
    "# 可变对象传参\n",
    "def change(a):\n",
    "    print(id(a),a)   # 指向的是同一个对象\n",
    "    a.append([4,5])\n",
    "    print(id(a),a)   # 一个新对象\n",
    " \n",
    "a=[1,2,3]\n",
    "print(id(a),a)\n",
    "change(a)\n",
    "print(id(a),a)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "armed-interim",
   "metadata": {},
   "source": [
    "## 函数参数类型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "infinite-arlington",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "123\n"
     ]
    }
   ],
   "source": [
    "# 必须参数\n",
    "# 必需参数须以正确的顺序传入函数。调用时的数量必须和声明时的一样。\n",
    "def printme( str ):\n",
    "   \"打印任何传入的字符串\"\n",
    "   print (str)\n",
    "   return\n",
    " \n",
    "# 调用 printme 函数，不加参数会报错\n",
    "printme(\"123\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "amateur-revelation",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "123 45\n"
     ]
    }
   ],
   "source": [
    "# 关键字参数 \n",
    "# 关键字参数和函数调用关系紧密，函数调用使用关键字参数来确定传入的参数值，允许函数调用时参数的顺序与声明时不一致。\n",
    "def printme( string , num ):\n",
    "   \"打印任何传入的字符串\"\n",
    "   print (string,str(num))\n",
    "   return\n",
    " \n",
    "#调用printme函数\n",
    "printme(num = 45, string = \"123\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "blocked-gasoline",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "名字:  runoob\n",
      "年龄:  50\n",
      "------------------------\n",
      "名字:  runoob\n",
      "年龄:  35\n"
     ]
    }
   ],
   "source": [
    "# 默认参数\n",
    "# 调用函数时，如果没有传递参数，则会使用默认参数。以下实例中如果没有传入 age 参数，则使用默认值\n",
    "\n",
    "def printinfo( name, age = 35 ):\n",
    "   \"打印任何传入的字符串\"\n",
    "   print (\"名字: \", name)\n",
    "   print (\"年龄: \", age)\n",
    "   return\n",
    " \n",
    "#调用printinfo函数\n",
    "printinfo( age=50, name=\"runoob\" )\n",
    "print (\"------------------------\")\n",
    "printinfo( name=\"runoob\" )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "available-kennedy",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "输出: \n",
      "70\n",
      "(60, 50)\n",
      "输出: \n",
      "70\n",
      "{'a': 'a', 'b': 'b'}\n"
     ]
    }
   ],
   "source": [
    "# 不定长参数\n",
    "# 你可能需要一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数，和上述 2 种参数不同，声明时不会命名\n",
    "# 加了星号 * 的参数会以元组(tuple)的形式导入，存放所有未命名的变量参数.如果在函数调用时没有指定参数，它就是一个空元组\n",
    "# 加了两个星号 ** 的参数会以字典的形式导入,其中参数变量名为键(必须遵守变量命名规则)，参数值为值\n",
    "\n",
    "def printinfo1( arg1, *vartuple ):\n",
    "   \"打印任何传入的参数\"\n",
    "   print (\"输出: \")\n",
    "   print (arg1)\n",
    "   print (vartuple)\n",
    "    \n",
    "def printinfo2( arg1, **vardict ):\n",
    "   \"打印任何传入的参数\"\n",
    "   print (\"输出: \")\n",
    "   print (arg1)\n",
    "   print (vardict)\n",
    " \n",
    "# 调用printinfo 函数\n",
    "printinfo1( 70, 60, 50 )\n",
    "printinfo2( 70, a=\"a\", b=\"b\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "infrared-maximum",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "6"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 星号 * 单独出现，星号 * 后的参数必须用关键字传入\n",
    "def f(a,*,b,c):\n",
    "    return a+b+c\n",
    "f(1,b=2,c=3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "handmade-status",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "10 20 30 40 50 60\n"
     ]
    }
   ],
   "source": [
    "# Python3.8 新增了一个函数形参语法 / 用来指明函数形参必须使用指定位置参数，/前的参数不能使用关键字参数的形式。\n",
    "# 例子中，形参 a 和 b 必须使用指定位置参数，c 或 d 可以是位置形参或关键字形参，而 e 和 f 要求为关键字形参\n",
    "def f(a, b, /, c, d, *, e, f):\n",
    "    print(a, b, c, d, e, f)\n",
    "f(10, 20, 30, d=40, e=50, f=60)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bright-outside",
   "metadata": {},
   "source": [
    "## 匿名函数\n",
    "* 使用 lambda 来创建匿名函数。\n",
    "* 所谓匿名，意即不再使用 def 语句这样标准的形式定义一个函数\n",
    "* lambda 函数拥有自己的命名空间，且**不能访问**自己参数列表之外或全局命名空间里的参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "colonial-december",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "相加后的值为 :  30\n",
      "相加后的值为 :  40\n"
     ]
    }
   ],
   "source": [
    "sum = lambda arg1, arg2: arg1 + arg2\n",
    " \n",
    "# 调用sum函数\n",
    "print (\"相加后的值为 : \", sum( 10, 20 ))\n",
    "print (\"相加后的值为 : \", sum( 20, 20 ))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "personal-marshall",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "22\n",
      "33\n"
     ]
    }
   ],
   "source": [
    "# 可以将匿名函数封装在一个函数内，这样可以使用同样的代码来创建多个匿名函数\n",
    "\n",
    "def myfunc(n):\n",
    "  return lambda a : a * n\n",
    " \n",
    "mydoubler = myfunc(2)\n",
    "mytripler = myfunc(3)\n",
    " \n",
    "print(mydoubler(11))\n",
    "print(mytripler(11))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "committed-geneva",
   "metadata": {},
   "source": [
    "## 模块\n",
    "* 一个模块只会被导入一次，不管你执行了多少次import\n",
    "* 一个模块被另一个程序第一次引入时，其主程序将运行"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "olympic-parameter",
   "metadata": {},
   "source": [
    "#### 模块导入方法\n",
    "* ```import module1[, module2[,... moduleN]```  \n",
    "可以使用模块名称来访问函数  \n",
    "* ```from modname import name1[, name2[, ... nameN]]```  \n",
    "从模块中导入一个指定的部分到当前命名空间中，不使用模块名直接调用。不会把被模块的名称放在当前的命名空间中  \n",
    "* ```from modname import *```  \n",
    "把一个模块的所有内容全都导入到当前的命名空间，由单一下划线（_）开头的名字不在此例  \n",
    "* ```import module1 as modname1[, module2 as modname2[,... moduleN as modnameN]```  \n",
    "导入模块同时重命名模块，使用模块别名来访问函数"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "featured-picking",
   "metadata": {},
   "source": [
    "#### 下划线 _ __ 开头的变量\n",
    "1. 公有变量名  \n",
    "以此类名称命名的对象，为公有对象，任何人都可以使用\n",
    "2. 半私有变量名_  \n",
    "    * 类外  \n",
    "    类外的半私有对象、私有对象，功能一致，均是在本模块中可以正常使用，但是不能被直接导入并调用（不能用'from module import *'导入）。如果一定要在模块外使用，那么需要导入本模块，然后使用（模块名.变量名）进行调用\n",
    "    * 类中  \n",
    "    类中的半私有对象，仅仅是概念上的私有，默认不要再类外进行调用。实际在类外，均可以使用（实例名.变量名/类名.变量名）进行调用\n",
    "3. 私有变量名__  \n",
    "    * 类外  \n",
    "    和半私有对象一样\n",
    "    * 类中  \n",
    "    类中的私有对象，在类外均不能直接调用，可以理解为真私有（但是，python中没有完全私有的对象，此种对象也是可以在类外进行调用的。对于出现在类中的私有属性或者私有方法，进行矫直，矫直方法就是在私有属性名、私有方法名前添加（_类名），如类 A里的__private标识符将被转换为_A__private。当类名全部以下划线命名的时候，Python就不再执行矫直）"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "african-eating",
   "metadata": {},
   "source": [
    "#### __name__属性\n",
    "如果我们想在模块被引入时，模块中的某一程序块不执行，我们可以用__name__属性来使该程序块仅在该模块自身运行时执行。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "lasting-choir",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "程序自身在运行\n"
     ]
    }
   ],
   "source": [
    "if __name__ == '__main__':\n",
    "   print('程序自身在运行')\n",
    "else:\n",
    "   print('我来自另一模块')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "unlikely-memorabilia",
   "metadata": {},
   "source": [
    "#### dir()函数\n",
    "内置的函数 dir() 可以找到模块内定义的所有名称。以一个字符串列表的形式返回"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "greater-intervention",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['__doc__',\n",
       " '__loader__',\n",
       " '__name__',\n",
       " '__package__',\n",
       " '__spec__',\n",
       " 'acos',\n",
       " 'acosh',\n",
       " 'asin',\n",
       " 'asinh',\n",
       " 'atan',\n",
       " 'atan2',\n",
       " 'atanh',\n",
       " 'ceil',\n",
       " 'comb',\n",
       " 'copysign',\n",
       " 'cos',\n",
       " 'cosh',\n",
       " 'degrees',\n",
       " 'dist',\n",
       " 'e',\n",
       " 'erf',\n",
       " 'erfc',\n",
       " 'exp',\n",
       " 'expm1',\n",
       " 'fabs',\n",
       " 'factorial',\n",
       " 'floor',\n",
       " 'fmod',\n",
       " 'frexp',\n",
       " 'fsum',\n",
       " 'gamma',\n",
       " 'gcd',\n",
       " 'hypot',\n",
       " 'inf',\n",
       " 'isclose',\n",
       " 'isfinite',\n",
       " 'isinf',\n",
       " 'isnan',\n",
       " 'isqrt',\n",
       " 'ldexp',\n",
       " 'lgamma',\n",
       " 'log',\n",
       " 'log10',\n",
       " 'log1p',\n",
       " 'log2',\n",
       " 'modf',\n",
       " 'nan',\n",
       " 'perm',\n",
       " 'pi',\n",
       " 'pow',\n",
       " 'prod',\n",
       " 'radians',\n",
       " 'remainder',\n",
       " 'sin',\n",
       " 'sinh',\n",
       " 'sqrt',\n",
       " 'tan',\n",
       " 'tanh',\n",
       " 'tau',\n",
       " 'trunc']"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import math as ma,numpy as np\n",
    "dir(ma)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "artificial-dancing",
   "metadata": {},
   "source": [
    "## 包\n",
    "* 目录只有包含一个叫做 __init__.py 的目录才会被认作是一个包，最简单的情况，放一个空的 :file:__init__.py就可以了。当然这个文件中也可以包含一些初始化代码或者为__all__变量赋值"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "celtic-loading",
   "metadata": {},
   "source": [
    "#### 一种可能的包结构的例子\n",
    "```\n",
    "sound/                          顶层包\n",
    "      __init__.py               初始化 sound 包\n",
    "      formats/                  文件格式转换子包\n",
    "              __init__.py\n",
    "              wavread.py\n",
    "              wavwrite.py\n",
    "              aiffread.py\n",
    "              aiffwrite.py\n",
    "              auread.py\n",
    "              auwrite.py\n",
    "              ...\n",
    "      effects/                  声音效果子包\n",
    "              __init__.py\n",
    "              echo.py\n",
    "              surround.py\n",
    "              reverse.py\n",
    "              ...\n",
    "      filters/                  filters 子包\n",
    "              __init__.py\n",
    "              equalizer.py\n",
    "              vocoder.py\n",
    "              karaoke.py\n",
    "              ...\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "harmful-article",
   "metadata": {},
   "source": [
    "用户可以每次只导入一个包里面的特定模块:  \n",
    "`import sound.effects.echo`  \n",
    "必须使用全名去访问:  \n",
    "`sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)`  \n",
    "还有一种导入子模块的方法是:  \n",
    "`from sound.effects import echo`  \n",
    "这同样会导入子模块: echo，并且他不需要那些冗长的前缀，所以他可以这样使用:  \n",
    "`echo.echofilter(input, output, delay=0.7, atten=4)`  \n",
    "或者直接导入一个函数或者变量:  \n",
    "`from sound.effects.echo import echofilter`"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "danish-preview",
   "metadata": {},
   "source": [
    "#### 从一个包中导入*\n",
    "Python 会进入文件系统，找到这个包里面所有的子模块，然后一个一个的把它们都导入进来。  \n",
    "但这个方法在 Windows 平台上工作的就不是非常好，因为 Windows 是一个不区分大小写的系统。  \n",
    "在 Windows 平台上，我们无法确定一个叫做 ECHO.py 的文件导入为模块是 echo 还是 Echo，或者是 ECHO。  \n",
    "为了解决这个问题，我们只需要提供一个精确包的索引。  \n",
    "导入语句遵循如下规则：如果包定义文件 \\_\\_init__.py 存在一个叫做 `__all__` 的列表变量，那么在使用 from package import * 的时候就把这个列表中的所有名字作为包内容导入。  \n",
    "作为包的作者，可别忘了在更新包之后保证 `__all__` 也更新了啊。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "static-modification",
   "metadata": {},
   "source": [
    "包还提供一个额外的属性`__path__`。这是一个目录列表，里面每一个包含的目录都有为这个包服务的__init__.py。这个功能并不常用，一般用来扩展包里面的模块。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "hidden-limitation",
   "metadata": {},
   "source": [
    "## 输入输出"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "protected-blend",
   "metadata": {},
   "outputs": [
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "请输入： 123421\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "你输入的内容是:  123421\n"
     ]
    }
   ],
   "source": [
    "str = input(\"请输入：\");\n",
    "print (\"你输入的内容是: \", str)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "arctic-poultry",
   "metadata": {},
   "source": [
    "## 异常处理\n",
    "```python\n",
    "try:\n",
    "    # 执行代码\n",
    "except:\n",
    "    # 发生异常时运行的代码\n",
    "else:\n",
    "    # 没有异常时执行的代码\n",
    "finally:\n",
    "    # 不论如何都会最终运行的代码，用于清理行为\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "reverse-bankruptcy",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python[conda env:torch38]",
   "language": "python",
   "name": "torch38"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
